import Base from './Base.js';
import { GRAPH_TYPES } from './Graph.enum.js';

import Point from '../Point';
/**
 * Bezier
 *
 * mod: orders of points: [startPoint, controlPoint1, controlPoint2, endPoint]
 */

class Bezier extends Base {
    constructor({ pos } = {}) {
        // console.log('===============> ', pos);
        super(...arguments);
        this.name = GRAPH_TYPES.BEZIER;
        this.a = pos.a;
        if (!this.points || !this.points.length) this.points = [{ ...pos }, { ...pos }, { ...pos }, { ...pos }];
        else {
            this.x = (this.points[0].x + this.points[3].x) / 2;
            this.y = (this.points[0].y + this.points[3].y) / 2;
        }
    }
    createPath() {
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.y, 5, 0, Math.PI * 2, false);
    }
    /**
     * isACCP: is Auto Computed Controll Points
     */
    initUpdate(start, end, isACCP = false, isStraight = false) {
        // console.log('Bezier.initUpdate: ', ...arguments);
        let a = Math.round(Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2))) / 2,
            x1 = start.x + (end.x - start.x) / 2,
            y1 = start.y - a,
            y2 = end.y + a;
        // // this.points[1] = { x: end.x, y: end.y };
        // // this.points[2] = { x: x1, y: y1 < 0 ? 0 : y1 };
        // // this.points[3] = { x: start.x, y: end.y };
        // // this.points[3] = { x: x1, y: y2 > this.ctxHeight ? this.ctxHeight : y2 };
        // this.points[1] = { x: x1, y: y1 < 0 ? 0 : y1 };
        // this.points[2] = { x: x1, y: y2 > this.ctxHeight ? this.ctxHeight : y2 };
        // this.points[3] = { x: end.x, y: end.y };
        if (isACCP) {
            this.autoComputedControlPoints(end, isStraight);
            this.points[3] = { x: parseInt(end.x), y: parseInt(end.y), a: null };
        } else {
            // this.points[1] = { x: x1, y: y1 < 0 ? 0 : y1 };
            // this.points[2] = { x: x1, y: y2 > this.ctxHeight ? this.ctxHeight : y2 };
            this.points[1] = { x: parseInt(x1), y: parseInt(y1) };
            this.points[2] = { x: parseInt(x1), y: parseInt(y2) };
            this.points[3] = { x: parseInt(end.x), y: parseInt(end.y), a: null };
        }
        this.x = (start.x + end.x) / 2;
        this.y = (start.y + end.y) / 2;
    }
    initCompleted() {
        if ((this.points && this.points.length < 4) || Point.equals(this.points[0], this.points[3])) return;
        let ps = this.points.concat();
        let cp = [
            new Point(ps[0].x, ps[0].y, ps[0].a),
            new Point(ps[1].x, ps[1].y, ps[1].a),
            new Point(ps[2].x, ps[2].y, ps[2].a),
            new Point(ps[3].x, ps[3].y, ps[3].a)
        ];
        let steps = 1 / (this.getLength(cp) / 100);
        let p1A = Point.getBezierPoint(steps, cp),
            p2A = Point.getBezierPoint(1 - steps, cp);

        this.points[0].a = this.points[0].h =
            cp[0].a === null || cp[0].a === undefined ? Math.round(p1A.angle(cp[0])) : cp[0].a; //eslint-disable-line
        this.points[3].a = this.points[3].h =
            cp[3].a === null || cp[3].a === undefined ? Math.round(cp[3].angle(p2A)) : cp[3].a; //eslint-disable-line
        // console.log(
        //     'Bezier.initCompleted: ',
        //     this.points,
        //     this.a,
        //     steps,
        //     p1A,
        //     p2A,
        //     Math.round(p1A.angle(cp[0])),
        //     Math.round(cp[3].angle(p2A))
        // ); //eslint-disable-line
    }
    autoComputedControlPoints(end, isStraight) {
        let ps = this.points.concat();
        let p0 = new Point(ps[0].x, ps[0].y, ps[0].a),
            p1 = new Point(ps[1].x, ps[1].y, ps[1].a),
            p2 = new Point(ps[2].x, ps[2].y, ps[2].a),
            // p3 = new Point(ps[3].x, ps[3].y, ps[3].a);
            p3 = new Point(end.x, end.y, end.a);
        // calculate the distance to control points
        let radius = p0.distance(p3) / Math.sqrt(2),
            d = radius * 0.6641; // clothoids factor

        let m1 = 1,
            m2 = 1;
        if (Point.getAngleDelta(end.angle(p0), p0.a) > 90) m1 = -1;
        if (Point.getAngleDelta(end.angle(p3), p3.a) > 90) m2 = -1;

        let straightStartAngle = p0.a === null || p0.a === undefined || isStraight,
            straightEndAngle = p3.a === null || p3.a === undefined || isStraight;
        p1 = straightStartAngle ? p0 : new Point(d * m1, 0).rotate(p0, p0.a).round();
        let p2A = straightEndAngle ? p3 : new Point(d * -m2, 0).rotate(p3, p3.a).round(),
            p2B = straightEndAngle ? p3 : new Point(d * +m2, 0).rotate(p3, p3.a).round();
        let bA = [p0, p1, p2A, p3],
            bB = [p0, p1, p2B, p3];
        p2 = this.getLength(bA) < this.getLength(bB) ? p2A : p2B;
        // this.points = [p0, p1, p2, p3];
        this.points[1] = { ...p1 };
        this.points[2] = { ...p2 };
        // console.log('Bezier.autoComputedControlPoints: ', radius, d, m1, p0, new Point(d * m1, 0).rotate(p0, p0.a)); //eslint-disable-line
        // console.log('Bezier.autoComputedControlPoints: ', p0, p1, p2, p3);
    }
    getLength(cp) {
        let length = 0;
        for (let i = 1; i < cp.length; i++) length += cp[i - 1].distance(cp[i]);
        return length;
    }
    // isStraight(cp) {
    //     if (Point.equals(cp[0], cp[1]) && Point.equals(cp[2], cp[3])) return true;
    //     let angle = Math.round(cp[3].angle(cp[0]));
    //     return cp[0].a === angle && cp[3].a === angle;
    // }

    drawController(scaling) {
        this.drawControlLine();
        super.drawController(scaling);
    }

    // 绘制控制贝塞尔角度的线
    drawControlLine() {
        // this.ctx.lineWidth = 0.5;
        this.ctx.lineWidth = this.lineWidth / 2;
        this.ctx.strokeStyle = '#00f';
        let yr = this.isReverse ? -1 : 1;

        // control points cannect line
        this.ctx.beginPath();
        // this.ctx.moveTo(this.points[0].x, this.points[0].y * yr);
        // this.ctx.lineTo(this.points[2].x, this.points[2].y * yr);
        // this.ctx.moveTo(this.points[1].x, this.points[1].y * yr);
        // this.ctx.lineTo(this.points[3].x, this.points[3].y * yr);
        this.ctx.moveTo(this.points[0].x, this.points[0].y * yr);
        this.ctx.lineTo(this.points[1].x, this.points[1].y * yr);
        this.ctx.moveTo(this.points[3].x, this.points[3].y * yr);
        this.ctx.lineTo(this.points[2].x, this.points[2].y * yr);
        this.ctx.stroke();

        // this.ctx.setLineDash([this.lineWidth / 2]);
        // this.ctx.lineDashOffset = 0;
        //control points
        // this.points.forEach(point => {
        //     this.ctx.beginPath();
        //     this.ctx.arc(point.x, point.y * yr, this.lineWidth / 3, 0, Math.PI * 2, false);
        //     this.ctx.stroke();
        // });
    }

    drawCenter(scaling) {
        this.x = (parseInt(this.points[0].x) + parseInt(this.points[3].x)) / 2;
        this.y = (parseInt(this.points[0].y) + parseInt(this.points[3].y)) / 2;
        // console.log('Bezier.drawCenter-this.points[0].x,y:', this.points[0].x, this.points[0].y);
        // console.log('Bezier.drawCenter-this.points[3].x,y:', this.points[3].x, this.points[3].y);
        // console.log('Bezier.drawCenter-x,y:', this.x, this.y, this.isReverse);
        super.drawCenter(scaling);
    }

    drawPath(ctx) {
        // console.log('Bezier.drawPath: ', ctx);
        ctx.lineWidth = this.lineWidth;
        ctx.strokeStyle = this.strokeStyle;
        let yr = this.isReverse ? -1 : 1;
        ctx.beginPath();
        ctx.moveTo(this.points[0].x, this.points[0].y * yr);
        ctx.bezierCurveTo(
            // this.points[2].x,
            // this.points[2].y * yr,
            // this.points[3].x,
            // this.points[3].y * yr,
            // this.points[1].x,
            // this.points[1].y * yr
            this.points[1].x,
            this.points[1].y * yr,
            this.points[2].x,
            this.points[2].y * yr,
            this.points[3].x,
            this.points[3].y * yr
        );
        // ctx.closePath();
        // ctx.stroke();
        // ctx.restore();
    }

    drawSelected(ctx) {
        console.log('Bezier.drawSelected: ', ctx);
        if (ctx) this.ctx = ctx;
        this.ctx.save();
        // this.ctx.lineWidth = this.lineWidth;
        // this.ctx.strokeStyle = this.strokeStyle;
        this.drawPath(this.ctx);
        this.ctx.stroke();
        this.ctx.restore();
    }

    draw(ctx) {
        if (ctx) this.ctx = ctx;

        this.ctx.save();
        // this.ctx.lineWidth = this.lineWidth;
        // this.ctx.strokeStyle = this.strokeStyle;
        // let yr = this.isReverse ? -1 : 1;
        // this.ctx.beginPath();
        // this.ctx.moveTo(this.points[0].x, this.points[0].y * yr);
        // this.ctx.bezierCurveTo(
        //     // this.points[2].x,
        //     // this.points[2].y * yr,
        //     // this.points[3].x,
        //     // this.points[3].y * yr,
        //     // this.points[1].x,
        //     // this.points[1].y * yr
        //     this.points[1].x,
        //     this.points[1].y * yr,
        //     this.points[2].x,
        //     this.points[2].y * yr,
        //     this.points[3].x,
        //     this.points[3].y * yr
        // );
        this.drawPath(this.ctx);
        this.ctx.stroke();
        this.ctx.restore();

        //绘制平移/更新图形锚点基准点
        this.drawAnchorPoint();
        //绘制未连接点 - 未避免车辆绘制，修改到Painter中调用
        // this.drawUnConnectPoints();
    }

    drawCached(ctx) {
        ctx.save();
        // this.drawPath(ctx);
        let penSize = 1 / this.scaling || 100;
        // ctx.fillStyle = Color.lightenDarkenColor(this.fillStyle, 0.3);
        // ctx.fill();
        ctx.lineWidth = penSize * 5;
        ctx.strokeStyle = 'rgba(0, 0, 255, 0.6)';
        ctx.setLineDash([penSize * 10, penSize * 10]);
        ctx.lineCap = 'round';
        ctx.stroke();
        ctx.restore();
    }
    drawPathLine(ctx, lineDashOffset) {
        // console.log('Bezier.drawPathLine-----');
        if (ctx) this.ctx = ctx;

        this.ctx.save();
        this.drawPath(this.ctx);
        this.ctx.stroke();
        this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)';
        this.ctx.lineCap = 'butt';
        this.ctx.setLineDash([this.ctx.lineWidth]);
        if (!lineDashOffset) {
            this._pathMarch.call(this, this.ctx);
            this.ctx.lineDashOffset = -this.offset;
        } else this.ctx.lineDashOffset = lineDashOffset;
        this.ctx.stroke();
        this.ctx.restore();

        //绘制平移/更新图形锚点基准点
        // this.drawAnchorPoint();
        //绘制未连接点 - 未避免车辆绘制，修改到Painter中调用
        // this.drawUnConnectPoints();
    }
    _pathMarch(ctx) {
        // console.log('Bezier._pathMarch-----');
        if (!this.offset || this.offset > ctx.lineWidth * 2) this.offset = 0;
        this.offset += ctx.lineWidth / 10;
        // console.log(this.offset);
    }
    _getPathDescription(points) {
        // let d = 'M' + points[0].x + ',' + points[0].y;
        // d += ' C' + points[2].x + ',' + points[2].y;
        // d += ' ' + points[3].x + ',' + points[3].y;
        // d += ' ' + points[1].x + ',' + points[1].y;
        let d = 'M' + points[0].x + ',' + points[0].y;
        d += ' C' + points[1].x + ',' + points[1].y;
        d += ' ' + points[2].x + ',' + points[2].y;
        d += ' ' + points[3].x + ',' + points[3].y;
        return d;
    }
    getSVGCodes() {
        // <path fill="none" stroke-linecap="round" stroke="rgba(0,0,211,0.62)" d="M-35000,85000C-35000,85000 -30000,85000 -30000,85000 " stroke-width="100"></path>
        let codes = '<path fill="none" stroke-linecap="round" ';
        codes += 'stroke="' + this.strokeStyle + '" ';
        codes += 'stroke-width="' + this.lineWidth + '" ';
        codes += 'd="' + this._getPathDescription(this.points) + '" ';
        codes += '></path>';
        return codes;
    }
}
export default Bezier;
